package com.yesep.learn.design.behavioral.strategy;

import com.yesep.learn.design.common.pojo.*;
import com.yesep.learn.design.common.util.*;

import java.util.*;

/**
 * 策略模式（Strategy Pattern），又称为政策模式，是一种行为型设计模式。
 * 它定义了一系列算法，并将每个算法封装起来，使它们可以互相替换，从而让算法的变化独立于使用算法的用户。
 * 策略模式的主要目的是将算法的定义与使用分开，也就是将算法的行为和环境分开，将算法的定义放在专门的策略类中，
 * 每一个策略类封装了一种实现算法，使用算法的环境类针对抽象策略类进行编程，符合“依赖倒转原则”。
 * <p>
 * 一、模式定义与结构
 * 定义：策略模式定义了一系列算法，并将每一个算法封装起来，使它们可以相互替换，且算法的变化独立于使用算法的客户。
 * <p>
 * 结构：策略模式通常包含三个主要角色：
 * <p>
 * 抽象策略（Strategy）角色：定义了一个公共接口，以封装一系列算法或行为。这个接口通常是一个抽象类或接口，声明了算法或行为的方法。
 * 具体策略（Concrete Strategy）角色：实现了抽象策略接口，封装了具体的算法或行为。
 * 环境（Context）角色：持有一个对抽象策略对象的引用，并在需要时调用策略对象的方法。环境类将客户端的请求委托给所选择的策略对象。
 * 二、工作原理
 * 在策略模式中，客户端根据需要选择并配置一个具体的策略对象，然后将其传递给环境类对象。
 * 环境类对象持有一个对策略对象的引用，并在需要执行算法时，通过该引用调用策略对象的方法。
 * 由于策略对象可以在运行时被替换，因此环境类对象可以在不修改其代码的情况下，通过改变策略对象来改变其行为。
 * <p>
 * 三、优点
 * 算法自由切换：策略模式提供了在运行时动态选择算法的能力，使得算法的选择更加灵活。
 * 符合开闭原则：策略模式支持在不修改原有系统的基础上，增加新的算法或行为，提高了系统的可扩展性。
 * 避免多重条件语句：使用策略模式可以避免在代码中编写大量的条件语句来选择不同的算法，从而提高了代码的可读性和可维护性。
 * 代码复用：策略模式将算法封装在独立的策略类中，使得这些算法可以被不同的环境类复用。
 * 四、缺点
 * 客户端必须了解所有策略：客户端必须知道所有的策略类，并自行决定使用哪一个策略类，这增加了客户端的复杂度。
 * 策略类数量可能过多：当系统中存在大量的策略时，会导致策略类的数量过多，增加了系统的复杂度和维护成本。
 * 五、应用场景
 * 策略模式适用于以下场景：
 * <p>
 * 当一个类有许多行为，并且这些行为在运行时需要根据不同的情况选择时。
 * 当需要在不同的情况下使用不同的算法或策略，并且这些算法或策略可以相互替换时。
 * 当算法或策略的实现经常变化，或者未来可能增加新的算法或策略时。
 * 六、示例
 * 以出行方式为例，可以定义一个旅行策略接口（TravelStrategy），然后为不同的出行方式（如乘坐飞机、乘坐火车、骑自行车等）实现具体的策略类。
 * 环境类（如PersonContext）持有一个对旅行策略对象的引用，并在需要时调用其方法来执行具体的出行方式。
 * 这样，当需要改变出行方式时，只需更换环境类中的策略对象即可，而无需修改环境类本身。
 */
public class Main {
    public static void main(String[] args) {
        List<Goods> goodsList = DemoUtil.createGoodsList();
        DoubleSummaryStatistics stats = ShoppingContext.calculateTotalPrice(goodsList, new StrategyA(), new StrategyB(), new StrategyC());
        // 输出统计信息
        System.out.println("Count: " + stats.getCount());
        System.out.println("Min: " + stats.getMin());
        System.out.println("Max: " + stats.getMax());
        System.out.println("Average: " + stats.getAverage());
    }

}
